package com.middleware.spring.context;


import com.middleware.spring.annotations.*;
import com.middleware.spring.awares.BeanNameAware;
import com.middleware.spring.beanDefinition.BeanDefinition;
import com.middleware.spring.initializing.InitializingBean;
import com.middleware.spring.processers.BeanPostProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class ApplicationContext {
    private static final Logger log = LoggerFactory.getLogger(ApplicationContext.class);

    protected static final String SINGLETON = "singleton";

    protected Class<?> configClass;

    // 核心容器：存放Bean名称和对应的Bean实例（单例）或BeanDefinition
    protected Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    protected Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    protected List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    public ApplicationContext() {
    }

    public ApplicationContext(Class<?> configClass) {

        this.configClass = configClass;
        //扫描包，解析成BeanDefinition
        scanBeans(configClass);

        //实例化Bean
        instantiateBeans();
    }

    public ApplicationContext(String  path){
        scanBeans(path);

        instantiateBeans();
    }

    protected void instantiateBeans() {
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (beanDefinition.isLazy()) {
                continue;
            }
            if (!beanDefinition.getScope().equals(SINGLETON)) {
                continue;
            }
            //判断一下单例池中是否有
            if (singletonObjects.containsKey(beanName)) {
                continue;
            }

            Object bean = instantiateBeans(beanName);

            singletonObjects.put(beanName, bean);
        }
    }

    protected Object instantiateBeans(String beanName){
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(Objects.isNull(beanDefinition)){
            return null;
        }
        Class<?> beanClass = beanDefinition.getBeanClass();
        if(beanClass == null){
            return null;
        }
        //实例化
        Object bean = createBean(beanClass);

        //属性注入
        populateBean(bean, beanClass);

        //aware 回调
        awareBean(bean, beanName);

        //前置处理器
        processorBefore(bean, beanName);

        //初始化
        initializingBean(bean);

        //后置处理器
        processorAfter(bean, beanName);

        return bean;
    }

    protected void processorAfter(Object bean, String beanName) {
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
        }
    }

    protected void initializingBean(Object bean) {
        if (bean instanceof InitializingBean) {
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    protected void awareBean(Object bean, String beanName) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
    }

    protected void processorBefore(Object bean, String beanName) {
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
        }
    }

    protected void populateBean(Object bean, Class<?> beanClass) {
        for (java.lang.reflect.Field field : beanClass.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                //获取属性类型
                Class<?> fieldType = field.getType();

                //获取属性对应的Bean
                Object fieldValue = getBean(fieldType);
                //将属性设置到bean中
                field.setAccessible(true);
                try {
                    field.set(bean, fieldValue);
                } catch (IllegalAccessException e) {}
            }
        }
    }

    public Object getBean(String fieldName) {
        //先从 单例池中获取
        Object bean = singletonObjects.get(fieldName);
        if (bean != null) {
            return bean;
        }

        bean = instantiateBeans(fieldName);
        if (bean == null) {
            return null;
        }

        BeanDefinition beanDefinition = beanDefinitionMap.get(fieldName);

        if(beanDefinition.getScope().equals(SINGLETON)){
            singletonObjects.put(fieldName, bean);
        }

        return bean;
    }

    public Object getBean(Class<?> clazz) {
        String beanName = Introspector.decapitalize(clazz.getSimpleName());
        Object bean = getBean(beanName);
        if(bean == null){
            //启动按照类型注入
            //遍历所有的BeanDefinition
            for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
                BeanDefinition beanDefinition = entry.getValue();
                //如果 clazz 是 beanClass 的父类
                if (clazz.isAssignableFrom(beanDefinition.getBeanClass())) {
                    beanName = Introspector.decapitalize(beanDefinition.getBeanClass().getSimpleName());
                    bean = getBean(beanName);
                    break;
                }
            }
        }
        return bean;
    }

    protected Object createBean(Class<?> beanClass){
        Object bean = null;
        try {
            bean = beanClass.getConstructor().newInstance();
        } catch (Exception e) {
            log.error("实例化Bean失败", e);
        }
        return bean;
    }

    protected void scanBeans(Class<?> configClass) {
        //从 configClass 中获取 @ComponentScan 注解
        ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        String path = componentScan.value();
        scanBeans( path);
    }
    protected void scanBeans(String path) {

        List<Class<?>> beanClassList = getBeanClassFromPackage(path);
        for (Class<?> clazz : beanClassList) {
            //如果实现了 BeanPostProcessor 接口
            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                BeanPostProcessor beanPostProcessor = null;
                try {
                    beanPostProcessor = (BeanPostProcessor) clazz.getConstructor().newInstance();
                } catch (InstantiationException |
                         IllegalAccessException |
                         InvocationTargetException |
                         NoSuchMethodException e) {
                    throw new RuntimeException(e);
                }
                beanPostProcessorList.add(beanPostProcessor);
            }else {
                //如果是普通类
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanClass(clazz);
                beanDefinition.setLazy(false);
                beanDefinition.setScope(SINGLETON);
                if(clazz.isAnnotationPresent(Lazy.class)){
                    beanDefinition.setLazy(true);
                }
                if(clazz.isAnnotationPresent(Scope.class)){
                    beanDefinition.setScope(clazz.getAnnotation(Scope.class).value());
                }

                //生成 beanName
                //spring底层自动生成beanname
                String beanName = Introspector.decapitalize(clazz.getSimpleName());
                Component annotation = clazz.getAnnotation(Component.class);
                if (annotation != null) {
                    String value = annotation.value();
                    if(!"".equals(value)){
                        beanName = value;
                    }
                }else {
                    String value = clazz.getAnnotation(Service.class).value();
                    if(!"".equals(value)){
                        beanName = value;
                    }
                }
                beanDefinitionMap.put(beanName, beanDefinition);
            }
        }

    }


    protected List<Class<?>> getBeanClassFromPackage(String path) {
        List<Class<?>> beanClassList = new ArrayList<>();
        // 获取类加载器
        ClassLoader classLoader = ApplicationContext.class.getClassLoader();

        path = path.replace(".", "/");

        URL resource = classLoader.getResource(path);
        if (resource == null) {
            log.warn("包路径不存在: {}", path);
            return beanClassList;
        }

        File file = new File(resource.getFile());
        // 递归扫描目录
        scanDirectory(file, path.replace("/", "."), beanClassList, classLoader);

        return beanClassList;
    }

    /**
     * 递归扫描目录中的类文件
     * @param directory 要扫描的目录
     * @param currentPackage 当前包名
     * @param beanClassList 存储Bean类的列表
     * @param classLoader 类加载器
     */
    protected void scanDirectory(File directory, String currentPackage,
                               List<Class<?>> beanClassList, ClassLoader classLoader) {
        if (!directory.exists() || !directory.isDirectory()) {
            return;
        }

        File[] files = directory.listFiles();
        if (files == null) {
            return;
        }

        for (File f : files) {
            if (f.isDirectory()) {
                // 递归扫描子目录，更新包名
                String subPackage = currentPackage + "." + f.getName();
                scanDirectory(f, subPackage, beanClassList, classLoader);
            } else if (f.getName().endsWith(".class")) {
                // 处理类文件
                processClassFile(f, currentPackage, beanClassList, classLoader);
            }
        }
    }

    /**
     * 处理类文件并检查注解
     */
    protected void processClassFile(File classFile, String currentPackage,
                                  List<Class<?>> beanClassList, ClassLoader classLoader) {
        try {
            // 获取简单类名（去掉.class后缀）
            String className = classFile.getName().replace(".class", "");
            // 构建完整类名
            String fullClassName = currentPackage + "." + className;

            // 排除内部类
            if (className.contains("$")) {
                return;
            }

            Class<?> clazz = classLoader.loadClass(fullClassName);
            if (clazz.isAnnotationPresent(Component.class) ||
                    clazz.isAnnotationPresent(Service.class)) {
                beanClassList.add(clazz);
            }
        } catch (ClassNotFoundException e) {
            log.error("加载类失败: {}", classFile.getName(), e);
        } catch (NoClassDefFoundError e) {
            log.warn("类定义不完整: {}, 错误: {}", classFile.getName(), e.getMessage());
        }
    }
}
